package com.ly.friend.service.user.Impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.ly.api.RemoteJudgeService;
import com.ly.api.domain.UserExeResult;
import com.ly.api.domain.dto.JudgeSubmitDTO;
import com.ly.api.domain.vo.UserQuestionResultVO;
import com.ly.common.core.constants.Constants;
import com.ly.common.core.domain.R;
import com.ly.common.core.enums.ProgramType;
import com.ly.common.core.enums.QuestionResType;
import com.ly.common.core.enums.ResultCode;
import com.ly.common.core.utils.ThreadLocalUtil;
import com.ly.common.security.exception.ServiceException;
import com.ly.friend.domain.question.Question;
import com.ly.friend.domain.question.QuestionCase;
import com.ly.friend.domain.question.es.QuestionES;
import com.ly.friend.domain.user.UserSubmit;
import com.ly.friend.domain.user.dto.UserSubmitDTO;
import com.ly.friend.elasticsearch.QuestionRepository;
import com.ly.friend.mapper.question.QuestionMapper;
import com.ly.friend.mapper.user.UserSubmitMapper;
import com.ly.friend.rabbit.JudgeProducer;
import com.ly.friend.service.user.IUserQuestionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserQuestionServiceImpl implements IUserQuestionService {
    @Autowired
    private QuestionRepository questionRepository;

    @Autowired
    private QuestionMapper questionMapper;

    @Autowired
    private RemoteJudgeService remoteJudgeService;

    @Autowired
    private JudgeProducer judgeProducer;

    @Autowired
    private UserSubmitMapper userSubmitMapper;

    @Override
    //后端接收到请求,获取参数,根据getProgramType判断用户提交代码语言类型

//    UserSubmitDTO（用户提交的数据，包括题目ID、代码、考试ID等）
//    JudgeSubmitDTO（判题服务需要的数据，包括题目信息、测试用例、用户代码等）
    public R<UserQuestionResultVO> submit(UserSubmitDTO submitDTO) {
        Integer programType = submitDTO.getProgramType();
        if(ProgramType.JAVA.getValue().equals(programType)){
            //按照Java逻辑处理
            JudgeSubmitDTO judgeSubmitDTO=assembleJudgeSubmitDTO(submitDTO);
//            remoteJudgeService.doJudgeJavaCode(judgeSubmitDTO)
            return remoteJudgeService.doJudgeJavaCode(judgeSubmitDTO);
        }
        throw new ServiceException(ResultCode.FAILED_NOT_SUPPORT_PROGRAM);
    }

    /**
     * 将用户提交的代码通过RabbitMQ异步发送给判题服务（目前仅支持Java）
     * @param submitDTO 用户提交的代码信息，包含代码内容、题目ID、编程语言类型等
     * @return true 提交成功 | 抛出异常 提交失败（不支持的编程语言）
     * @throws ServiceException 如果编程语言不支持，抛出业务异常(ResultCode.FAILED_NOT_SUPPORT_PROGRAM)
     */
    @Override
    public boolean rabbitSubmit(UserSubmitDTO submitDTO) {
        // 1. 获取用户提交的编程语言类型
        Integer programType = submitDTO.getProgramType();
        if(ProgramType.JAVA.getValue().equals(programType)){
            //按照Java逻辑处理, 组装判题服务需要的DTO（包括代码、测试用例等信息）
            JudgeSubmitDTO judgeSubmitDTO=assembleJudgeSubmitDTO(submitDTO);
            // 通过RabbitMQ生产者将判题任务发送到消息队列（异步处理）
//             把参数给rabbitmq,但是没执行判题结果,目前实现是同步调用远程服务
            judgeProducer.produceMsg(judgeSubmitDTO);
            // 返回true表示消息已成功提交到队列（注意：不表示判题已完成）
            return true;
        }
        throw new ServiceException(ResultCode.FAILED_NOT_SUPPORT_PROGRAM);

    }

    /**
     * 根据考试ID、题目ID和时间戳查询用户的判题结果
     * @param examId 考试ID
     * @param questionId 题目ID
     * @param currentTime 提交时间标识（用于区分同一题目的多次提交）
     * @return UserQuestionResultVO 包含判题状态、执行结果、用例详情等
     */
    @Override
    public UserQuestionResultVO exeResult(Long examId, Long questionId, String currentTime) {
        //把结果获取出来
        // 1. 从ThreadLocal中获取当前用户ID（基于登录上下文）
        Long userId = ThreadLocalUtil.get(Constants.USER_ID, Long.class);
        // 2. 查询数据库获取用户提交记录
        UserSubmit userSubmit = userSubmitMapper.selectCurrentUserSubmit(
                userId, questionId, examId, currentTime);

        // 3. 构建返回VO对象
        UserQuestionResultVO resultVO = new UserQuestionResultVO();

        // 4. 判题结果不存在的情况（可能还在判题中）
        if (userSubmit == null) {
            resultVO.setPass(QuestionResType.IN_JUDGE.getValue()); // 设置状态为"判题中"
        }
        // 5. 存在判题结果
        else {
            resultVO.setPass(userSubmit.getPass());
            resultVO.setExeMessage(userSubmit.getExeMessage());
            if (StrUtil.isNotEmpty(userSubmit.getCaseJudgeRes())) {
                resultVO.setUserExeResultList(JSON.parseArray(userSubmit.getCaseJudgeRes(), UserExeResult.class));
            }
        }

        return resultVO;
    }

    private JudgeSubmitDTO assembleJudgeSubmitDTO(UserSubmitDTO submitDTO) {
        Long questionId = submitDTO.getQuestionId();
        //orElse,findbyId返回的是Optional对象,并不是数据本身,如果能查出数据,返回数据本身
        //查不出来数据,返回null
        // 1. 查询题目信息（优先ES，不存在则查MySQL并缓存）
        QuestionES questionES = questionRepository.findById(questionId).orElse(null);
        JudgeSubmitDTO judgeSubmitDTO=new JudgeSubmitDTO();
        if(questionES!=null){
            BeanUtil.copyProperties(questionES,judgeSubmitDTO);
        }else{
            Question question = questionMapper.selectById(questionId);
            BeanUtil.copyProperties(question,judgeSubmitDTO);
            questionES=new QuestionES();
            // 2. 组装 JudgeSubmitDTO
            BeanUtil.copyProperties(question, questionES);
            questionRepository.save(questionES);
        }
        // 3. 设置用户信息（从 ThreadLocal 获取用户ID）
        judgeSubmitDTO.setUserId(ThreadLocalUtil.get(Constants.USER_ID,Long.class));
        judgeSubmitDTO.setExamId(submitDTO.getExamId());
        judgeSubmitDTO.setProgramType(submitDTO.getProgramType());

        // 4.拼接用户代码和题目主函数
        judgeSubmitDTO.setUserCode(codeConnect(submitDTO.getUserCode(),questionES.getMainFuc()));

        // 5. 解析测试用例（从 ES 的 JSON 字符串转换成 List）
        List<QuestionCase> questionCaseList = JSONUtil.toList(questionES.getQuestionCase(), QuestionCase.class);

        List<String> inputList = questionCaseList.stream().map(QuestionCase::getInput).toList();
        judgeSubmitDTO.setInputList(inputList);
        List<String> outputList = questionCaseList.stream().map(QuestionCase::getOutput).toList();
        judgeSubmitDTO.setOutputList(outputList);
        return judgeSubmitDTO;
    }
    private String codeConnect(String userCode, String mainFunc) {
        String targetCharacter = "}";
        int targetLastIndex = userCode.lastIndexOf(targetCharacter);
        if (targetLastIndex != -1) {
            return userCode.substring(0, targetLastIndex) + "\n" + mainFunc + "\n" + userCode.substring(targetLastIndex);
        }
        throw new ServiceException(ResultCode.FAILED);
    }

}
